home *** CD-ROM | disk | FTP | other *** search
Text File | 2000-04-25 | 25.8 KB | 803 lines | [TEXT/CWIE] |
- /*
- File: StorageClassShim.c
-
- Contains: USB Storage Class Shim
-
- Version: 1.0
-
- Copyright: © 1998-2000 by Apple Computer, Inc., all rights reserved.
- */
-
- // Universal Headers
-
- #include <Devices.h>
- #include <DriverGestalt.h>
- #include <DriverServices.h>
- #include <Folders.h>
- #include <MacTypes.h>
- #include <Resources.h>
- #include <USB.h>
-
- // Project Headers
- #include "StorageClassShim.h"
- #include "StorageClassPublicAPI.h"
- #include "StorageClassShimDS.h"
- #include "StorageDeviceConfiguration.h"
-
- // Enumerations for the range of Unittable entries
- // in which InstallDriverFromMemory will try to install the driver
- enum
- {
- kUnitTableFloppyRefNum = 4,
- kUnitTableEntryStart = 48,
- kUnitTableDriverResource = 128
- };
-
-
- // These are all variables that are global to the Shim
- static Boolean shimInFile;
- static FSSpec shimFSSpec;
- static UInt32 gNotificationTokenCount = 0;
- static UInt32 gNotificationToken[10] = {0,0,0,0,0,0,0,0,0,0};
- static IOCompletionUPP gInitCompletionUPP = nil;
- static IOCompletionUPP gDeviceInfoCompletionUPP = nil;
- static IOCompletionUPP gTerminateCompletionUPP = nil;
-
- // Here are all the prototypes for functions static to the shim
- static UInt32 MyUSBGetVersion(void);
- static void myNotificationCallback (USBDeviceNotificationParameterBlock *pb);
- static void HandleAddNotification( USBDeviceRef theDevRef, UInt16 usbVendor, UInt16 usbProduct, UInt8 usbSubClass, Boolean isDeviceNotification );
- static void HandleRemoveNotification( USBDeviceRef theDevRef, Boolean isDeviceNotification );
-
- // Functions used by the shim to Install and Remove USB Expert notifications
- static Boolean InstallUSBNotifications( void );
- static Boolean RemoveUSBNotifications( void );
-
- static OSStatus ShimOpenDriver(USBDeviceRef theDevRef, UInt16 usbVendor, UInt16 usbProduct, UInt8 usbSubClass, Boolean isDeviceNotification );
- static OSStatus ShimCloseDriver(USBDeviceRef theDevRef);
-
- // Internal Completion routines that have UPPs allocated.
- static void InitializeCntrlCallCompletionProc( ParmBlkPtr paramBlock );
- static void GetDeviceInfoCallCompletionProc( ParmBlkPtr paramBlock );
- static void RetryUnitTableConfig( USBPB *usbPB);
- static void TerminateCntrlCallCompletionProc( ParmBlkPtr paramBlock );
-
- // Supporting functions
- static OSStatus GetRegEntryIDForUSBReference( USBDeviceRef usbRefNum, USBDeviceRef *parentsDeviceRef, RegEntryIDPtr regEntryIDPtr, Boolean isDeviceNotification );
-
- #pragma mark --
- #pragma mark Code Fragment Manager Functions
- /******************************** Code Fragment Manager Functions ******************************************/
-
- // This is the Code Fragment Initialize routine. This is called by the Code Fragment Manager when
- // the code fragment containing the shim is loaded. We use this function to save the the FSSpec
- // for the file containing the shim and the Unit Table Driver.
- OSErr CFragInitRoutine(CFragInitBlockPtr initBlkPtr)
- {
- shimInFile = false;
-
- if (CFragHasFileLocation(initBlkPtr->fragLocator.where))
- {
- shimInFile = true;
- shimFSSpec = *(initBlkPtr->fragLocator.u.onDisk.fileSpec); // save the FSSpec, in case we need it later
- }
-
- return noErr;
- }
-
- // This is the Code Fragment Terminate routine. This is called by the Code Fragment Manager when
- // the code fragment containing the shim is being removed.
- void CFragTermRoutine( void )
- {
- RemoveUSBNotifications();
- TerminateStorageDriverServices();
-
- // Free resources used by our UPPs. Check to see if the are nil, if so no need to dispose.
- if ( gInitCompletionUPP != nil )
- {
- DisposeRoutineDescriptor( gInitCompletionUPP );
- }
-
- if ( gDeviceInfoCompletionUPP != nil )
- {
- DisposeRoutineDescriptor( gDeviceInfoCompletionUPP );
- }
-
- if ( gTerminateCompletionUPP != nil )
- {
- DisposeRoutineDescriptor( gTerminateCompletionUPP );
- }
- }
-
- #pragma mark --
- #pragma mark USB Manager/Expert Functions
- /******************************** USB Manager/Expert Functions ******************************************/
- UInt32 MyUSBGetVersion(void)
- {
- UInt32 version;
-
- if ((Ptr) USBGetVersion != (Ptr) kUnresolvedCFragSymbolAddress)
- version = USBGetVersion();
- else
- version = 0; // version of USB is less than 1.3
- return version;
- }
-
- // This is the initialize entry point to the shim. This function is exported so that it can
- // be called when the shim is loaded.
- OSStatus USBShim( void )
- {
- if ( MyUSBGetVersion() < kMinimumUSBMgrVersion )
- {
- // This does not meet the minimum USB Manager version, leave now.
- return noErr; // Is there an error that should be returned? Does the USB Expert check?
- }
-
- gInitCompletionUPP = NewIOCompletionProc(InitializeCntrlCallCompletionProc);
- gDeviceInfoCompletionUPP = NewIOCompletionProc(GetDeviceInfoCallCompletionProc);
- gTerminateCompletionUPP = NewIOCompletionProc(TerminateCntrlCallCompletionProc);
-
- // The USB Manager looks to be the one we want, or can use, prepare for usage.
- InitializeStorageDriverServices();
-
- // Install notifications last because we could get notified immediately
- InstallUSBNotifications();
- return noErr;
- }
-
- #pragma mark --
- #pragma mark USB Notification Functions
- /******************************** USB Notification Functions ******************************************/
- // This is the notification routine that the Expert will call when a Mass Storage Device
- // has been attached to the USB or removed from the USB.
- void myNotificationCallback(USBDeviceNotificationParameterBlock *pb)
- {
- Boolean isADeviceNotification = false;
-
- switch(pb->usbDeviceNotification) // why were we notified?
- {
- case kNotifyAddDevice: // because mass storage device appeared
- isADeviceNotification = true; // Set flag saying this is a device notification
- // and then pass through to next case
- case kNotifyAddInterface: // because mass storage interface appeared
- {
- HandleAddNotification(pb->usbDeviceRef, pb->usbVendor, pb->usbProduct, pb->usbSubClass, isADeviceNotification);
- }
- break;
-
- case kNotifyRemoveDevice: // because a mass storage device or interface disappeared
- isADeviceNotification = true; // Set flag saying this is a device notification
- // and then pass through to next case
- case kNotifyRemoveInterface: // because a mass storage device or interface disappeared
- {
- HandleRemoveNotification( pb->usbDeviceRef, isADeviceNotification );
- }
- break;
-
- default:
- {
- }
- break;
- }
- }
-
- void HandleAddNotification( USBDeviceRef theDevRef, UInt16 usbVendor, UInt16 usbProduct, UInt8 usbSubClass, Boolean isDeviceNotification )
- {
- ShimOpenDriver(theDevRef, usbVendor, usbProduct, usbSubClass, isDeviceNotification);
- }
-
- void HandleRemoveNotification( USBDeviceRef theDevRef, Boolean isDeviceNotification )
- {
- #pragma unused ( isDeviceNotification )
- ShimCloseDriver( theDevRef );
- }
-
- // This routine is used by the shim to install its USB notification procs
- Boolean InstallUSBNotifications( void )
- {
- USBDeviceNotificationParameterBlock pb;
-
- // Setup notification for Mass Storage Class Devices
- pb.usbDeviceNotification = kNotifyAnyEvent; // tell me about everything
- pb.usbClass = kDriverClassID; // tell me about the specified class
- pb.usbSubClass = kDriverSubclassID; // tell me about the specified subclass
- pb.usbProtocol = kUSBAnyProtocol; // tell me about all protocols for this vendor/product
- pb.usbVendor = kDriverVendorID; // Only notify me for this specific vendor
- pb.usbProduct = kDriverProductID; // and for this specific product
- pb.result = noErr;
- pb.callback = (USBDeviceNotificationCallbackProcPtr) &myNotificationCallback;
- pb.refcon = nil;
- USBInstallDeviceNotification (&pb);
- if ( pb.result == noErr )
- {
- gNotificationToken[gNotificationTokenCount] = pb.token;
- gNotificationTokenCount++; // Zero based array,increment to get true count
- }
-
- return true;
- }
-
- // This routine is used by the shim to remove its USB notification procs
- Boolean RemoveUSBNotifications( void )
- {
- while ( gNotificationTokenCount > 0 )
- {
- gNotificationTokenCount--; // Zero based array, decrement the counter first
- if ( gNotificationToken[gNotificationTokenCount] !=0 )
- {
- USBRemoveDeviceNotification( gNotificationToken[gNotificationTokenCount] );
- gNotificationToken[gNotificationTokenCount] = 0;
- }
- }
-
- return true;
- }
-
- #pragma mark --
- #pragma mark Open Driver Functions
- static OSStatus SendInitializeControlCall (DriverInfoPtr currentDriveInfoPtr);
- static void SendGetDeviceInfoDriverGestaltCall (DriverInfoPtr currentDriveInfoPtr);
-
- // This function is called by our notification routine to load a Unit Table driver when the device
- // we specified in our notification setup is attached
- OSStatus ShimOpenDriver(USBDeviceRef theDevRef, UInt16 usbVendor, UInt16 usbProduct, UInt8 usbSubClass, Boolean isDeviceNotification )
- {
- OSStatus theErr = noErr;
- Handle hDrvrResource;
- THz currentZone;
- DriverRefNum drvrRefNum;
- void *pTheStorageClassDispatchTable;
- CFragSymbolClass symClass;
- CFragConnectionID connID;
- DriverInfoPtr currentDriveInfoPtr;
- RegEntryID usbRegEntryID;
- RegEntryIDPtr usbRegEntryIDPtr;
-
- // We have been notified of a new device, check to see if we already
- // have installed a driver the USB Device Ref.
- currentDriveInfoPtr = FindDriverInfoByUSBDeviceRef( theDevRef );
- if ( currentDriveInfoPtr != nil )
- {
- // We already have a driver loaded for this device, return
- return noErr;
- }
-
- // Check if we have a driver for the subclass installed without the device
- currentDriveInfoPtr = GetDriverInfoHeadPtr();
- while ( currentDriveInfoPtr != nil )
- {
- if(( currentDriveInfoPtr->usbDeviceRef == 0 ) && (currentDriveInfoPtr->usbSubClass == usbSubClass )
- && (currentDriveInfoPtr->usbVendor == usbVendor ) && (currentDriveInfoPtr->usbProduct == usbProduct ))
- {
- // We have found a driver candidate
- drvrRefNum = currentDriveInfoPtr->drvrRefNum;
- currentDriveInfoPtr->usbDeviceRef = theDevRef;
- break;
- }
-
- currentDriveInfoPtr = currentDriveInfoPtr->nextDriverInfo;
- }
-
- // if the currentDriveInfoPtr is nil, we know that we don't have a DriveInfo element
- // for this new device yet, let's build one
- if ( currentDriveInfoPtr == nil )
- {
- short oldResFileID = 0;
-
- SetResLoad(true);
- oldResFileID = CurResFile(); // get the current resource file ID
-
- // No driver has been loaded for this USBDeviceRef, find the driver's 'ndrv' resource
- if (shimInFile)
- {
- short myResFileID = 0;
-
- myResFileID = OpenShimResourceFork();
- UseResFile(myResFileID); // point at the shim file
-
- currentZone = GetZone ();
- SetZone ( SystemZone() );
- hDrvrResource = Get1Resource('ndrv', kUnitTableDriverResource); // read in the driver from a ndrv resource
- DetachResource(hDrvrResource); // Detach the resource so it hangs around in the system heap
- SetZone (currentZone);
-
- UseResFile(oldResFileID); // point at the original file
- CloseShimResourceFork(); // Make sure the resource file is closed
- }
-
- // We have found the driver's 'ndrv' resource, install it into the UnitTable
- if (hDrvrResource)
- {
- long drvrSize;
- Ptr pDrvrInMemory;
- USBDeviceRef parentsDeviceRef;
-
- // Lock the Driver Resource in memory
- HLock(hDrvrResource);
-
- // Get the resource information needed to install the Driver
- pDrvrInMemory = *hDrvrResource;
- drvrSize = GetHandleSize(hDrvrResource);
-
- usbRegEntryIDPtr = &usbRegEntryID;
- theErr = GetRegEntryIDForUSBReference( theDevRef, &parentsDeviceRef, usbRegEntryIDPtr, isDeviceNotification );
- if ( theErr != noErr )
- {
- usbRegEntryIDPtr = nil;
- }
-
- // Check if this is a floppy subclass device
- if( usbSubClass == kUSBStorageUFISubclass )
- {
- // If a floppy subclass, try the traditional floppy UnitTable spot first
- theErr = InstallDriverFromMemory(pDrvrInMemory, drvrSize, nil, usbRegEntryIDPtr, kUnitTableFloppyRefNum, kUnitTableFloppyRefNum, &drvrRefNum);
- if ( theErr != noErr )
- {
- // We couldn't get the traditional spot, try normal range
- // We try from kUnitTableEntryStart to HighestUnitNumber+1 which will try all entries in the table and the are all full and
- // the table hasn't grown to its maximum size, trying a number bigger than HighestUnitNumber will force the table to grow.
- theErr = InstallDriverFromMemory(pDrvrInMemory, drvrSize, nil, usbRegEntryIDPtr, kUnitTableEntryStart, HighestUnitNumber()+1, &drvrRefNum);
- }
- }
- else
- {
- // Install the driver
- // We try from kUnitTableEntryStart to HighestUnitNumber+1 which will try all entries in the table and the are all full and
- // the table hasn't grown to its maximum size, trying a number bigger than HighestUnitNumber will force the table to grow.
- theErr = InstallDriverFromMemory(pDrvrInMemory, drvrSize, nil, usbRegEntryIDPtr, kUnitTableEntryStart, HighestUnitNumber()+1, &drvrRefNum);
- }
-
- if ( theErr != noErr )
- {
- // The driver could not be loaded, the shim will return the error and abort the driver load
- return theErr;
- }
-
- // Save the Driver refnum to remove the driver when the remove notification is recieved
- currentDriveInfoPtr = AddDriverInfoPtr();
- if (currentDriveInfoPtr == nil )
- {
- // We couldn't get any memory, just bail for now.
- // Should probably figure a graceful way to handle this.
- return memFullErr;
- }
-
- currentDriveInfoPtr->usbDeviceRef = theDevRef;
- currentDriveInfoPtr->parentsDeviceRef = parentsDeviceRef;
- currentDriveInfoPtr->usbSubClass = usbSubClass;
- currentDriveInfoPtr->usbVendor = usbVendor;
- currentDriveInfoPtr->usbProduct = usbProduct;
- currentDriveInfoPtr->drvrRefNum = drvrRefNum;
- currentDriveInfoPtr->drvrHndlInMemory = hDrvrResource;
- }
- }
-
- // Get the Storage class dispatch table
- currentZone = GetZone ();
- SetZone ( SystemZone() );
-
- theErr = FindSymbol(connID, "\pTheStorageClassDispatchTable", (Ptr *)&pTheStorageClassDispatchTable, &symClass);
- SetZone (currentZone);
-
- // If no error occured, pass the dispatch table pointer to the Driver
- if (theErr == noErr)
- {
- currentDriveInfoPtr->theSetupTable.usbDeviceRef = theDevRef;
- currentDriveInfoPtr->theSetupTable.usbParentRef = currentDriveInfoPtr->parentsDeviceRef;
- currentDriveInfoPtr->theSetupTable.usbSubClass = usbSubClass;
- currentDriveInfoPtr->theSetupTable.usbVendor = usbVendor;
- currentDriveInfoPtr->theSetupTable.usbProduct = usbProduct;
- currentDriveInfoPtr->theSetupTable.shimDispatchTable = GetShimDispatchTablePtr();
- currentDriveInfoPtr->theSetupTable.theStorageClassDispatchTable = pTheStorageClassDispatchTable;
-
-
- theErr = SendInitializeControlCall ( currentDriveInfoPtr );
- }
- else
- {
- // We will get to this point if there was an error on either the FindSymbol call
- // if an error occurs, we should remove the driver from the unittable
- ShimCloseDriver(theDevRef);
- }
-
- return theErr;
- }
-
- OSStatus SendInitializeControlCall (DriverInfoPtr currentDriveInfoPtr)
- {
- OSStatus theErr;
- USBStorageClassSetupTablePtr theSetupTable;
-
- theSetupTable = ¤tDriveInfoPtr->theSetupTable;
-
- // Set the Dispatch table so that the Unit Table driver can communicate with the class driver
- BlockZero( ¤tDriveInfoPtr->controlPB, sizeof( CntrlParam ));
- currentDriveInfoPtr->controlPB.ioCompletion = gInitCompletionUPP;
- currentDriveInfoPtr->controlPB.ioVRefNum = 0;
- currentDriveInfoPtr->controlPB.ioCRefNum = currentDriveInfoPtr->drvrRefNum;
- currentDriveInfoPtr->controlPB.csCode = kInitializeDeviceAccess;
- *((UInt32 *) ¤tDriveInfoPtr->controlPB.csParam[0]) = (UInt32) theSetupTable;
- theErr = PBControlAsync( (ParmBlkPtr) ¤tDriveInfoPtr->controlPB);
- if ( theErr != noErr )
- {
- // An error occurred on the kInitializeDeviceAccess control
- // call and it couldn't be sent, there is nothing more that
- // can be done, so remove this driver from the UnitTable
- ShimCloseDriver(currentDriveInfoPtr->usbDeviceRef);
- }
-
- return theErr;
- }
-
- void InitializeCntrlCallCompletionProc( ParmBlkPtr paramBlock )
- {
- CntrlParam *ourCntrlPB;
- DriverInfoPtr currentDriveInfoPtr;
- OSStatus theErr;
-
- ourCntrlPB = (CntrlParam *) paramBlock;
- currentDriveInfoPtr = FindDriverInfoByDrvrRef( ourCntrlPB->ioCRefNum );
- theErr = currentDriveInfoPtr->controlPB.ioResult;
- if ( theErr == noErr )
- {
- if ( currentDriveInfoPtr->hasDialog == true )
- {
- RemoveNotificationDialog( currentDriveInfoPtr->drvrRefNum, currentDriveInfoPtr->messageNumber );
- }
-
- SendGetDeviceInfoDriverGestaltCall ( currentDriveInfoPtr );
- }
- else if ( theErr == kClassNotConfiguredError )
- {
- BlockZero( ¤tDriveInfoPtr->configAgainPB, sizeof(USBPB));
-
- currentDriveInfoPtr->configAgainPB.pbLength = sizeof(USBPB);
- currentDriveInfoPtr->configAgainPB.pbVersion = kUSBCurrentPBVersion;
- currentDriveInfoPtr->configAgainPB.usbCompletion = &RetryUnitTableConfig;
- currentDriveInfoPtr->configAgainPB.usbRefcon = (UInt32) currentDriveInfoPtr;
- currentDriveInfoPtr->configAgainPB.usbReference = currentDriveInfoPtr->usbDeviceRef;
- currentDriveInfoPtr->configAgainPB.usbReqCount = 100;
- currentDriveInfoPtr->configAgainPB.usbFlags = kUSBTaskTimeFlag;
-
- theErr = USBDelay( ¤tDriveInfoPtr->configAgainPB );
- if( theErr == kUSBPending )
- {
- theErr = noErr;
- }
- }
-
- if ( theErr != noErr )
- {
- // An error occurred on either kInitializeDeviceAccess control call
- // or on the USBDelay call. In either case, there is nothing that
- // can be done, so remove this driver from the UnitTable
- ShimCloseDriver(currentDriveInfoPtr->usbDeviceRef);
- }
- }
-
- void SendGetDeviceInfoDriverGestaltCall (DriverInfoPtr currentDriveInfoPtr)
- {
- // Get the Vendor Name of the device from the UnitTable driver
- DriverGestaltParam *theDGPB;
- OSStatus theErr;
-
- theDGPB = (DriverGestaltParam *) ¤tDriveInfoPtr->controlPB;
-
- BlockZero(theDGPB, sizeof(DriverGestaltParam));
-
- theDGPB->ioCompletion = (ProcPtr) gDeviceInfoCompletionUPP;
- theDGPB->ioCRefNum = currentDriveInfoPtr->drvrRefNum;
- theDGPB->csCode = kDriverGestaltCode;
- theDGPB->driverGestaltSelector = kdgDeviceModelInfo;
- theErr = PBStatusAsync((ParamBlockRec *) theDGPB);
- if ( theErr != noErr )
- {
- // An error an we we not able to get the Device info data
- // We must use the default data instead.
- PStrCopy(currentDriveInfoPtr->VendorProductStr,"\pUnknown Device");
- }
- }
-
- void GetDeviceInfoCallCompletionProc( ParmBlkPtr paramBlock )
- {
- DriverGestaltParam *theDGPB;
- DriverInfoPtr currentDriveInfoPtr;
- OSStatus theErr;
- DriverGestaltDeviceModelInfoResponse *theDeviceInfo;
-
- theDGPB = (DriverGestaltParam *) paramBlock;
- currentDriveInfoPtr = FindDriverInfoByDrvrRef( theDGPB->ioCRefNum );
- theErr = theDGPB->ioResult;
- if( theErr == noErr )
- {
- theDeviceInfo = *(GetDriverGestaltDeviceModelInfoResponse(theDGPB));
- }
- else
- {
- theDeviceInfo = nil;
- }
-
- if( (theDeviceInfo != nil) && ( theDeviceInfo->vendorName != nil ))
- {
- PStrCopy(currentDriveInfoPtr->VendorProductStr,theDeviceInfo->vendorName);
- if( theDeviceInfo->productName != nil )
- {
- PStrCat(currentDriveInfoPtr->VendorProductStr,"\p ");
- PStrCat(currentDriveInfoPtr->VendorProductStr,theDeviceInfo->productName);
- }
- }
- else
- {
- BlockZero(theDGPB, sizeof(DriverGestaltParam));
-
- theDGPB->ioCRefNum = currentDriveInfoPtr->drvrRefNum;
- theDGPB->csCode = kDriverGestaltCode;
- theDGPB->driverGestaltSelector = kdgDeviceType;
- theErr = PBStatusSync((ParamBlockRec *) theDGPB);
- switch (GetDriverGestaltDevTResponse(theDGPB)->deviceType )
- {
- case kdgTapeType:
- {
- PStrCopy(currentDriveInfoPtr->VendorProductStr,"\pUnknown Tape Drive");
- }
- break;
-
- case kdgProcessorType:
- {
- PStrCopy(currentDriveInfoPtr->VendorProductStr,"\pUnknown Processor Device");
- }
- break;
-
- case kdgWormType:
- {
- PStrCopy(currentDriveInfoPtr->VendorProductStr,"\pUnknown WORM Drive");
- }
- break;
-
- case kdgCDType:
- {
- PStrCopy(currentDriveInfoPtr->VendorProductStr,"\pUnknown CD-ROM Drive");
- }
- break;
-
- case kdgFloppyType:
- {
- PStrCopy(currentDriveInfoPtr->VendorProductStr,"\pUnknown Floppy Disk Drive");
- }
- break;
-
- case kdgRemovableType:
- {
- PStrCopy(currentDriveInfoPtr->VendorProductStr,"\pUnknown Removable Media Drive");
- }
- break;
-
- case kdgDiskType:
- {
- PStrCopy(currentDriveInfoPtr->VendorProductStr,"\pUnknown Hard Disk Drive");
- }
- break;
-
- default:
- {
- PStrCopy(currentDriveInfoPtr->VendorProductStr,"\pUnknown Device");
- }
- }
- }
- }
-
- void RetryUnitTableConfig( USBPB *usbPB)
- {
- DriverInfoPtr currentDriveInfoPtr;
- OSStatus theErr;
-
- currentDriveInfoPtr = (DriverInfoPtr) usbPB->usbRefcon;
-
- theErr = SendInitializeControlCall ( currentDriveInfoPtr );
- }
-
-
- #pragma mark --
- #pragma mark Close Driver Functions
- static OSStatus SendTerminateControlCall (DriverInfoPtr currentDriveInfoPtr);
-
- OSStatus ShimCloseDriver(USBDeviceRef theDevRef)
- {
- OSStatus theErr = noErr;
- DriverInfoPtr currentDriveInfoPtr;
-
- currentDriveInfoPtr = FindDriverInfoByUSBDeviceRef( theDevRef );
- if ( currentDriveInfoPtr == nil )
- {
- // There was no device with this USB Device Ref, just leave.
- return noErr;
- }
-
- if ( currentDriveInfoPtr->drvrRefNum == 0 )
- {
- // There was no UT driver loaded for this USB Device Ref, just leave.
- return noErr;
- }
-
- if ( currentDriveInfoPtr->hasDialog == true )
- {
- // This driver has a visible dialog, remove it
- RemoveNotificationDialog( currentDriveInfoPtr->drvrRefNum, currentDriveInfoPtr->messageNumber );
- }
-
- // We need to inform the UnitTable driver that it can no longer talk to the device.
- // The UnitTable driver needs to allow the class driver to be removed.
- theErr = SendTerminateControlCall ( currentDriveInfoPtr );
-
- return theErr;
- }
-
- OSStatus SendTerminateControlCall ( DriverInfoPtr currentDriveInfoPtr )
- {
- OSStatus theErr;
-
- // Set the Dispatch table so that the Unit Table driver can communicate with the class driver
- BlockZero( ¤tDriveInfoPtr->controlPB, sizeof( CntrlParam ));
- currentDriveInfoPtr->controlPB.ioVRefNum = 0;
- currentDriveInfoPtr->controlPB.ioCRefNum = currentDriveInfoPtr->drvrRefNum;
- currentDriveInfoPtr->controlPB.csCode = kTerminateDeviceAccess;
-
- theErr = PBControlSync( (ParmBlkPtr) ¤tDriveInfoPtr->controlPB);
- TerminateCntrlCallCompletionProc( (ParmBlkPtr) ¤tDriveInfoPtr->controlPB);
- return noErr;
- }
-
- void TerminateCntrlCallCompletionProc( ParmBlkPtr paramBlock )
- {
- CntrlParam *ourCntrlPB;
- DriverInfoPtr currentDriveInfoPtr;
- OSStatus theErr;
- Boolean doDriverRemoval = true;
- VCBPtr vol;
-
- ourCntrlPB = (CntrlParam *) paramBlock;
- currentDriveInfoPtr = FindDriverInfoByDrvrRef( ourCntrlPB->ioCRefNum );
- theErr = currentDriveInfoPtr->controlPB.ioResult;
- if ( theErr != noErr )
- {
- // The terminate control call failed, is there anything that
- // can be done at this point?
- // We will try to unmount all volumes just in case we can
- //return;
- }
-
- vol = (VCBPtr) (GetVCBQHdr())->qHead;
- while (vol)
- {
- // Check to see if this volume belongs to the driver
- // that is being removed
- if( vol->vcbDRefNum == currentDriveInfoPtr->drvrRefNum)
- {
- theErr = UnmountVol( nil, vol->vcbVRefNum );
- // Check if unmount volume returns a file busy err
- if (theErr == fBsyErr)
- {
- doDriverRemoval = false;
- }
- }
-
- vol = (VCBPtr) vol->qLink;
- }
-
- // if Do Removal is true, remove the drivers, else if Do Removal is false,
- // display the reattach dialog box.
- if ( doDriverRemoval == true )
- {
- theErr = RemoveDriver(currentDriveInfoPtr->drvrRefNum, false);
- if ( theErr == noErr )
- {
- // The driver was successfully closed and removed,
- // free all associated resources.
- HUnlock( currentDriveInfoPtr->drvrHndlInMemory );
- DisposeHandle( currentDriveInfoPtr->drvrHndlInMemory );
- RemoveDriverInfoPtr( currentDriveInfoPtr );
- }
- }
- else
- {
- vol = (VCBPtr) (GetVCBQHdr())->qHead;
-
- while (vol)
- {
- // Check to see if this volume belongs to the driver that is being removed
- if( vol->vcbDRefNum == currentDriveInfoPtr->drvrRefNum)
- {
- theErr = Eject( nil, vol->vcbVRefNum);
- }
-
- vol = (VCBPtr) vol->qLink;
- }
-
- // The device is already gone, clear the USB ref
- currentDriveInfoPtr->usbDeviceRef = 0;
- DisplayNotifcationDialog(currentDriveInfoPtr->drvrRefNum, kUSBStorageEventDeviceWasRemoved);
- }
- }
-
-
- #pragma mark --
- #pragma mark Shim Support Functions
- /******************************** Shim Support Functions ******************************************/
- // These are the routines that the Shim needs to support its operations. These includes initialization
- // routines, Unit Table driver matching and loading routines and shim termination routines.
-
- // These two functions give us a convenient way for any part of the shim to open
- // and close its resource fork
- static int resOpenCount = 0;
- static short resFileRef = 0;
-
- short OpenShimResourceFork( void )
- {
- if (shimInFile)
- {
- if ( resOpenCount == 0 )
- {
- // If we have not already opened the file, open it now
- resFileRef = FSpOpenResFile(&shimFSSpec, fsRdPerm);
- if ( resFileRef !=0 )
- {
- resOpenCount++;
- }
- }
- }
- else
- {
- resFileRef = 0;
- }
-
- return resFileRef;
- }
-
- void CloseShimResourceFork( void )
- {
- if ( ( resOpenCount !=0 ) && ( resFileRef != 0 ))
- {
- resOpenCount--;
- }
-
- if (( resOpenCount == 0 ) && ( resFileRef != 0 ))
- {
- CloseResFile(resFileRef);
- resFileRef = 0;
- }
- }
-
- OSStatus GetRegEntryIDForUSBReference( USBDeviceRef usbRefNum, USBDeviceRef *parentsDeviceRef, RegEntryIDPtr regEntryIDPtr, Boolean isDeviceNotification )
- {
- OSStatus err = noErr;
- RegEntryIter cookie;
- Boolean done;
-
- err = RegistryEntryIDInit(regEntryIDPtr);
- if (err != noErr)
- {
- return err;
- }
-
- err = RegistryEntryIterateCreate(&cookie);
- if (err != noErr)
- {
- return err;
- }
-
- if ( isDeviceNotification == true )
- {
- err = RegistryEntrySearch(&cookie, kRegIterDescendants, regEntryIDPtr, &done, "deviceRef", (const void *)&usbRefNum, (RegPropertyValueSize) sizeof(USBDeviceRef));
- *parentsDeviceRef = 0;
- }
- else
- {
- RegPropertyValueSize refPropSize = sizeof(USBDeviceRef);
-
- err = RegistryEntrySearch(&cookie, kRegIterDescendants, regEntryIDPtr, &done, "interfaceRef", (const void *)&usbRefNum, (RegPropertyValueSize) sizeof(USBDeviceRef));
- err = RegistryPropertyGet( regEntryIDPtr, "parent-deviceRef", (void *) parentsDeviceRef, &refPropSize);
- }
-
- RegistryEntryIterateDispose(&cookie);
- return err;
- }